package com.mamingchao.concurrent.threads_communication3;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * ArrayList 不是线程安全的
 * List 存放element，然后在通过 ++ size，这是两步操作；
 * 有可能 list里面已经有6个元素了，size还没完成++，就会造成这个问题
 *
 * Created by mamingchao on 2020/9/19.
 */
public class WithProplemWay {


//   A线程更新list，对于B lists是不可见的，或者可见不及时
//    static List<Integer> lists = new ArrayList<>();
    /**
     * 这个地方，加上volatile，比不加效果好（效果好的意思是说sleep 比不加时间短，也能有期望输出打印）
     * 但是 这个lists事实上是 真正list数据的引用，volatile的也是这个引用，所以 马老师的说法，这个地方加上volatile 有效果这件事 也很奇怪
     */
//    volatile static List<Integer> lists = new ArrayList<>();

    /**
     * ArrayList 是线程不安全的，这里用 synchronizedList
     */
    volatile static List<Integer> lists = Collections.synchronizedList(new LinkedList<>());

    static void add(Integer e){
        lists.add(e);
    }

    static int size(){
        return lists.size();
    }


    public static void main(String[] args) {

        Thread a = new Thread(() -> {

            for (int i = 0; i < 10; i++) {
                lists.add(i);
                System.out.println(i);
                try {
                    TimeUnit.MILLISECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread b = new Thread( ()->{
           while (true) {
               int size = size();
               /**
                * 下面这个System.out.print 注释掉，这个while就会一直loop，进不去判断
                * 如果这个注释打开，if就能进去
                * 这是什么原理我没有想明白，难道是 系统输出触发了 size的更新？
                * 马老师说的是 a线程更新了List数据，但是对线程B是不可见的
                * 那就是 系统输出 触发线程b 去获取list里的数据，导致List数据对B变成可见了（这个是我自己的理解）
                * ，但是没有volatile 修饰，这个数据肯定是不准的，当注释掉sleep时，会更明显
                */


               System.out.println("size-" + size);
               if (size == 5) {
                   System.out.println("Thread b has receive the notification");
                   break;
               }
           }
        });


        b.start();
        a.start();
    }

}
